
class dcu2lsu0_seq_lib extends uvm_sequence_library #(tr_dcu2lsu0);
  `uvm_object_utils(dcu2lsu0_seq_lib)
  `uvm_sequence_library_utils(dcu2lsu0_seq_lib)
  
  function new(string name="dcu2lsu0_seq_lib");
    super.new(name);
    init_sequence_library();
  endfunction
endclass

class dcu2lsu0_simple_sequence extends uvm_sequence #(tr_dcu2lsu0);
  `uvm_object_utils(dcu2lsu0_simple_sequence)
  `uvm_add_to_seq_lib(dcu2lsu0_simple_sequence, dcu2lsu0_seq_lib)
  `uvm_declare_p_sequencer(dcu2lsu0_sequencer)
  
	tr_dcu2lsu0 tr;
  tr_lsu2dcu0 req;
  
	virtual task body();
	  while(1) begin
      while(p_sequencer.q.size == 0)
        @(posedge p_sequencer.sysif.clk);
      req = p_sequencer.q.pop_front();
      if(req.ls)
        break;
    end
    `uvm_create(tr);
    tr.did = req.arid;
    tr.did.rand_mode(0);
    assert(tr.randomize());
    `uvm_send(tr)
	endtask
endclass

class dcu2lsu1_seq_lib extends uvm_sequence_library #(tr_dcu2lsu1);
  `uvm_object_utils(dcu2lsu1_seq_lib)
  `uvm_sequence_library_utils(dcu2lsu1_seq_lib)
  
  function new(string name="dcu2lsu1_seq_lib");
    super.new(name);
    init_sequence_library();
  endfunction
endclass

class dcu2lsu1_simple_sequence extends uvm_sequence #(tr_dcu2lsu1);
  `uvm_object_utils(dcu2lsu1_simple_sequence)
  `uvm_add_to_seq_lib(dcu2lsu1_simple_sequence, dcu2lsu1_seq_lib)
  `uvm_declare_p_sequencer(dcu2lsu1_sequencer)
  
	tr_dcu2lsu1 tr;
  tr_lsu2dcu1 req;
  
	virtual task body();
    while(p_sequencer.q.size == 0)
      @(posedge p_sequencer.sysif.clk);
    req = p_sequencer.q.pop_front();
    `uvm_create(tr);
    tr.sid = req.did;
    tr.sid.rand_mode(0);
    assert(tr.randomize());
    `uvm_send(tr)
	endtask
endclass

class lsu_seq_lib extends uvm_sequence_library#(uvm_sequence_item);
  `uvm_object_utils(lsu_seq_lib)
  `uvm_sequence_library_utils(lsu_seq_lib)
  
  function new(string name="lsu_seq_lib");
    super.new(name);
    init_sequence_library();
  endfunction
endclass

class lsu_simple_sequence extends uvm_sequence#(uvm_sequence_item);
  `uvm_object_utils(lsu_simple_sequence)
  `uvm_add_to_seq_lib(lsu_simple_sequence, lsu_seq_lib)
  `uvm_declare_p_sequencer(lsu_sequencer)
    
	tr_isu2lsu trisu;
  tr_rfu2lsu trrfu;
  
	virtual task body();
	  `uvm_create_on(trisu, p_sequencer.isu_seqr);
	  assert(trisu.randomize());
	  trisu.ls.rand_mode(0);
	  trisu.st.rand_mode(0);
	  trisu.ld.rand_mode(0);
    fork
      begin
    	  if(p_sequencer.isu_seqr != null)
          p_sequencer.isu_seqr.grab(this);
          `uvm_send(trisu);
///        `uvm_do_on(trisu, p_sequencer.isu_seqr);
    	  if(p_sequencer.isu_seqr != null)
          p_sequencer.isu_seqr.ungrab(this);
      end
      begin
        bit bt[3];
        bt = '{default : '0};
        if(!trisu.ls) begin
          case(trisu.ld)
            vmemld_byte,
            vmemld_ubyte:  bt[0] = '1;
            vmemld_half,
            vmemld_uhalf:  bt[1] = '1;
            default:       bt[2] = '1;
          endcase
        end else begin
          case(trisu.st)
            memst_byte:  bt[0] = '1;
            memst_half:  bt[1] = '1;
            default:     bt[2] = '1;
          endcase
        end
        @(trisu.start);
        repeat(MCV+1)
          @(posedge p_sequencer.sysif.clk);
    	  if(p_sequencer.rfu_seqr != null)
          p_sequencer.rfu_seqr.grab(this);        
        `uvm_do_on_with(trrfu, p_sequencer.rfu_seqr, {
          foreach(b[i]){
            bt[1] -> ((b[i] + imm) & 'h01) == '0;
            bt[2] -> ((b[i] + imm) & 'h03) == '0;
            b[i] == b[0];
            ((b[i] + imm) >> (WID_IDX_OS + even_odd_bit_table[p_sequencer.ptyp]))
            == (p_sequencer.vpn >> even_odd_bit_table[p_sequencer.ptyp]);
          }
        });
    	  if(p_sequencer.rfu_seqr != null)
          p_sequencer.rfu_seqr.ungrab(this);
      end
    join_any
	endtask
endclass

class test_lsu_env extends uvm_env;
  lsu_agent agent;
  
  virtual tlm_sys_if.mods sysif;

  `uvm_component_utils_begin(test_lsu_env)
  `uvm_component_utils_end
  
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
///    set_config_int("core.ife*", "fw_trans", 1);
    uvm_config_db#(uvm_bitstream_t)::set(this, "*", "is_dcu_reactive", 1'b1);
    uvm_config_db#(uvm_bitstream_t)::set(this, "*", "is_isu_reactive", 1'b1);
    agent = lsu_agent::type_id::create("lsu_agent", this);
  endfunction
  
  virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
  endfunction
  
  virtual task run_phase(uvm_phase phase);
  endtask

  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new
endclass

class lsu_test extends uvm_test;
  test_lsu_env env;
  rand vvpn_t vpn;
  rand vpage_typ_e ptyp;
  
///  constraint va{
///    (vpn.msk & page_mask_table[ptyp]) == '0;
///    solve ptyp before vpn;
///  };
    
  `uvm_component_utils_begin(lsu_test)
    `uvm_field_int(vpn, UVM_ALL_ON)
    `uvm_field_enum(vpage_typ_e, ptyp, UVM_ALL_ON)
  `uvm_component_utils_end
  
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    assert(this.randomize());
    vpn.msk = vpn.msk & ~page_mask_table[ptyp];
    
  	uvm_config_db#(virtual xpip_intf)::set(this, "*", "inf", top.inf);
  	uvm_config_db#(virtual tlm_sys_if)::set(this, "*", "sysif", top.sysif); 
  	
  	uvm_config_db#(uvm_bitstream_t)::set(this, "*", "vpn", vpn);
  	uvm_config_db#(uvm_bitstream_t)::set(this, "*", "ptyp", ptyp);
  	
///  	uvm_config_db#(uvm_object_wrapper)::set(this,"*.isu_sequencer.run_phase", "default_sequence", isu2lsu_seq_lib::type_id::get());
  	uvm_config_db#(uvm_object_wrapper)::set(this,"*.dcu0_sequencer.run_phase", "default_sequence", dcu2lsu0_seq_lib::type_id::get());
  	uvm_config_db#(uvm_object_wrapper)::set(this,"*.dcu1_sequencer.run_phase", "default_sequence", dcu2lsu1_seq_lib::type_id::get());
 	  uvm_config_db#(uvm_object_wrapper)::set(this,"*.top_seqr.run_phase", "default_sequence", lsu_seq_lib::type_id::get());
 	  
  	uvm_config_db#(uvm_sequence_lib_mode)::set(this, "*", "default_sequence.selection_mode", UVM_SEQ_LIB_RAND);   ///UVM_SEQ_LIB_ITEM

  	uvm_config_db#(int unsigned)::set(this, "*", "default_sequence.sequence_count", 100);
  	uvm_config_db#(int unsigned)::set(this, "*", "default_sequence.min_random_count", 100);
  	uvm_config_db#(int unsigned)::set(this, "*", "default_sequence.max_random_count", 100);
  	
    uvm_config_db#(time)::set(this, "*", "runDelay", 6ns);

    env = test_lsu_env::type_id::create("env", this);
  endfunction
  
   virtual function void end_of_elaboration_phase(uvm_phase phase);
    set_report_verbosity_level_hier(UVM_FULL); ///UVM_FULL UVM_MEDIUM UVM_HIGH UVM_LOW
  endfunction
    
  virtual task run_phase(uvm_phase phase);
  	tr_ifu2isu tr;

///    #20ns;
///  	tr = new();
///  	assert(tr.randomize());
///  	tr.fetchReq = '1;
///  	tr.pc = 32'h12300;
///  	tr.tid = $random;
///  	tr.cancel = '{default : '0};
    
///  	void'(env.ife_agent.ise_driver.nb_transport_ise(tr, tr));
    
  endtask

  function new(string name = "test_ife", uvm_component parent);
    super.new(name, parent);
  endfunction : new  
endclass